﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace Collections.TreeCollections
{
    /// <summary>
    /// Tree Object basic Tree object
    /// </summary>
    public abstract class TreeObject : ICloneable
    {
        #region Property
        /// <summary>
        /// Object Identify
        /// </summary>
        public TreeNodeIdentify ID { get { return _id; } }
        /// <summary>
        /// Object Name
        /// </summary>
        public virtual string Name { get { return _name; } }
        public string TypeName { get { return this.GetType().Name; } }

        public Tree TreeOwner { get; internal set; }
        #endregion

        #region Symbol
        private readonly static string _XML_SYMBOL_ID = "ID";
        private readonly static string _XML_SYMBOL_Class = "Class";
        #endregion

        #region Fields
        private TreeNodeIdentify _id;
        private string _name;
        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="id"></param>
        protected internal TreeObject(TreeNodeIdentify id)
        {
            _id = id;
            _name = this.GetType().Name;
        }

        /// <summary>
        /// Get the path from current tree to root
        /// </summary>
        /// <returns></returns>
        public TreeObject[] GetTreePath()
        {
            List<TreeObject> path = new List<TreeObject>();

            TreeObject tmpObj = this;
            for (INonRoot nonRoot = this as INonRoot; nonRoot != null
                ; tmpObj = (TreeObject)nonRoot.Parent, nonRoot = tmpObj as INonRoot)
            {
                path.Add((TreeObject)nonRoot);

            }

            path.Add(tmpObj);
            return path.ToArray<TreeObject>();
        }

        #region XML Parser
        /// <summary>
        /// To xml element
        /// </summary>
        /// <returns></returns>
        public virtual XElement ToXElem()
        {
            XElement xelem = new XElement(this._name);
            xelem.Add(new XAttribute(_XML_SYMBOL_ID, this._id.ToString()));
            xelem.Add(new XAttribute(_XML_SYMBOL_Class, this.GetType().FullName));

            return xelem;
        }
        /// <summary>
        /// XParse to information
        /// </summary>
        /// <param name="xelem"></param>
        /// <returns></returns>
        public static TreeObject XmlParser(XElement xelem, TreeRegisterClass treeRegister)
        {
            string idStr = xelem.Attribute(_XML_SYMBOL_ID).Value;
            string classStr = xelem.Attribute(_XML_SYMBOL_Class).Value;

            TreeNodeIdentify id = new TreeNodeIdentify(idStr);

            TreeObjectRegisterClass objRegister = treeRegister[classStr];
            TreeObject newObj = objRegister.Constructor(id, null);

            objRegister.XmlParser(xelem, newObj);

            return newObj;
        }
        #endregion

        #region Equals
        /// <summary>
        /// Determines whether the Sepecified FeatureModel.Collections.TreeCollections.TreeObject
        /// equals to current FeatureModel.Collections.TreeCollections.TreeObject
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            TreeObject treeObj = obj as TreeObject;
            if (treeObj == null)
            {
                return false;
            }
            return this._id.Equals(treeObj._id);
        }
        /// <summary>
        /// base.GetHashCode();
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        #endregion

        public override string ToString()
        {
            return string.Format("{0}: {1}"
                , _name, _id);
        }

        public abstract Object Clone();
    }
}
